package com.woniuxy.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author 饶志
 * @version 1.0
 * @since 2025-07-11  15:32
 */
@Component
public class RedisUtil {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 给一个指定的 key 值附加过期时间
     *
     * @param key  要设置过期时间的键
     * @param time 过期时间，单位为秒
     * @return 如果设置成功返回 true，否则返回 false
     */
    public boolean expire(String key, long time) {
        return redisTemplate.expire(key, time, TimeUnit.SECONDS);
    }

    /**
     * 根据 key 获取过期时间
     *
     * @param key 要查询过期时间的键
     * @return 键的剩余过期时间，单位为秒；如果键不存在或没有设置过期时间返回 -1
     */
    public long getTime(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 根据 key 检查是否存在该键
     *
     * @param key 要检查的键
     * @return 如果键存在返回 true，否则返回 false
     */
    public boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 移除指定 key 的过期时间，使其永久有效
     *
     * @param key 要移除过期时间的键
     * @return 如果移除成功返回 true，否则返回 false
     */
    public boolean persist(String key) {
        return redisTemplate.boundValueOps(key).persist();
    }

    //- - - - - - - - - - - - - - - - - - - - -  String类型 - - - - - - - - - - - - - - - - - - - -

    /**
     * 根据 key 获取值
     *
     * @param key 键
     * @return 值；如果键不存在返回 null
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     * 将值放入缓存
     *
     * @param key   键
     * @param value 值
     */
    public void set(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 将值放入缓存并设置时间
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)，-1 为无期限
     */
    public void set(String key, Object value, long time) {
        if (time > 0) {
            redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
        } else {
            redisTemplate.opsForValue().set(key, value);
        }
    }

    /**
     * 批量添加 key (重复的键会覆盖)
     *
     * @param keyAndValue 键值对映射
     */
    public void batchSet(Map<String, String> keyAndValue) {
        redisTemplate.opsForValue().multiSet(keyAndValue);
    }

    /**
     * 批量添加 key-value 只有在键不存在时，才添加
     * map 中只要有一个 key 存在，则全部不添加
     *
     * @param keyAndValue 键值对映射
     */
    public void batchSetIfAbsent(Map<String, String> keyAndValue) {
        redisTemplate.opsForValue().multiSetIfAbsent(keyAndValue);
    }

    /**
     * 对一个 key-value 的值进行加减操作
     * 如果该 key 不存在将创建一个 key 并赋值该 number
     * 如果 key 存在，但 value 不是长整型，将报错
     *
     * @param key    键
     * @param number 要增加或减少的值
     * @return 操作后的新值
     */
    public Long increment(String key, long number) {
        return redisTemplate.opsForValue().increment(key, number);
    }

    /**
     * 对一个 key-value 的值进行加减操作
     * 如果该 key 不存在将创建一个 key 并赋值该 number
     * 如果 key 存在，但 value 不是纯数字，将报错
     *
     * @param key    键
     * @param number 要增加或减少的值
     * @return 操作后的新值
     */
    public Double increment(String key, double number) {
        return redisTemplate.opsForValue().increment(key, number);
    }

    /**
     * 根据通配符模式删除匹配的键（注意：生产环境需谨慎使用，避免大范围扫描）
     *
     * @param pattern 通配符模式（如 "user:followList:userId:1:*"）
     */
    public void delByPattern(String pattern) {
        // 获取所有匹配模式的键
        Set<String> keys = redisTemplate.keys(pattern);
        if (keys != null && !keys.isEmpty()) {
            // 批量删除键
            redisTemplate.delete(keys);
        }
    }

    //- - - - - - - - - - - - - - - - - - - - -  set类型 - - - - - - - - - - - - - - - - - - - -

    /**
     * 向 Set 集合中添加数据
     *
     * @param key   键
     * @param value 值
     */
    public void sAdd(String key, Object value) {
        redisTemplate.opsForSet().add(key, value);
    }

    /**
     * 从 Set 集合中移除数据
     *
     * @param key   键
     * @param value 值
     */
    public void sRemove(String key, Object value) {
        redisTemplate.opsForSet().remove(key, value);
    }

    /**
     * 获取多个 Set 集合的交集
     *
     * @param keys 键的集合
     * @return 交集的结果
     */
    public Set<Object> getSetIntersect(String key1, String key2) {
        return redisTemplate.opsForSet().intersect(key1, key2);
    }

    /**
     * 将数据放入 set 缓存
     *
     * @param key   键
     * @param value 值
     */
    public void sSet(String key, String value) {
        redisTemplate.opsForSet().add(key, value);
    }

    /**
     * 获取变量中的值
     *
     * @param key 键
     * @return 变量中的所有值组成的集合
     */
    public Set<Object> members(String key) {
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * 随机获取变量中指定个数的元素
     *
     * @param key   键
     * @param count 要获取的元素个数
     * @return 随机获取的元素组成的集合
     */
    public List<Object> randomMembers(String key, long count) {
        return redisTemplate.opsForSet().randomMembers(key, count);
    }

    /**
     * 随机获取变量中的元素
     *
     * @param key 键
     * @return 随机获取的元素；如果集合为空返回 null
     */
    public Object randomMember(String key) {
        return redisTemplate.opsForSet().randomMember(key);
    }

    /**
     * 弹出变量中的元素
     *
     * @param key 键
     * @return 弹出的元素；如果集合为空返回 null
     */
    public Object pop(String key) {
        return redisTemplate.opsForSet().pop(key);
    }

    /**
     * 获取变量中值的长度
     *
     * @param key 键
     * @return 变量中值的数量
     */
    public long size(String key) {
        return redisTemplate.opsForSet().size(key);
    }

    /**
     * 根据 value 从一个 set 中查询，是否存在
     *
     * @param key   键
     * @param value 值
     * @return 如果存在返回 true，否则返回 false
     */
    public boolean sHasKey(String key, Object value) {
        return redisTemplate.opsForSet().isMember(key, value);
    }

    /**
     * 检查给定的元素是否在变量中
     *
     * @param key 键
     * @param obj 元素对象
     * @return 如果存在返回 true，否则返回 false
     */
    public boolean isMember(String key, Object obj) {
        return redisTemplate.opsForSet().isMember(key, obj);
    }

    /**
     * 转移变量的元素值到目的变量
     *
     * @param key     源变量的键
     * @param value   要转移的元素值
     * @param destKey 目的变量的键
     * @return 如果转移成功返回 true，否则返回 false
     */
    public boolean move(String key, String value, String destKey) {
        return redisTemplate.opsForSet().move(key, value, destKey);
    }

    /**
     * 批量移除 set 缓存中元素
     *
     * @param key    键
     * @param values 要移除的元素
     */
    public void remove(String key, Object... values) {
        redisTemplate.opsForSet().remove(key, values);
    }

    /**
     * 通过给定的 key 求 2 个 set 变量的差值
     *
     * @param key     源变量的键
     * @param destKey 目标变量的键
     * @return 差值组成的集合
     */
    public Set<Object> difference(String key, String destKey) {
        return redisTemplate.opsForSet().difference(key, destKey);
    }

    //- - - - - - - - - - - - - - - - - - - - -  hash类型 - - - - - - - - - - - - - - - - - - - -

    /**
     * 获取Hash中指定字段的值
     *
     * @param key   缓存键
     * @param field 字段名
     * @return 字段值
     */
    public Object hGet(String key, String field) {
        return redisTemplate.opsForHash().get(key, field);
    }

    /**
     * 设置Hash中指定字段的值
     *
     * @param key   缓存键
     * @param field 字段名
     * @param value 字段值
     */
    public void hSet(String key, String field, Object value) {
        redisTemplate.opsForHash().put(key, field, value);
    }

    /**
     * 加入缓存
     *
     * @param key 键
     * @param map 键值对映射
     */
    public void add(String key, Map<String, String> map) {
        redisTemplate.opsForHash().putAll(key, map);
    }

    /**
     * 获取 key 下的所有 hashkey 和 value
     *
     * @param key 键
     * @return 包含所有 hashkey 和 value 的映射
     */
    public Map<Object, Object> getHashEntries(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 验证指定 key 下有没有指定的 hashkey
     *
     * @param key     键
     * @param hashKey 要验证的 hashkey
     * @return 如果存在返回 true，否则返回 false
     */
    public boolean hashKey(String key, String hashKey) {
        return redisTemplate.opsForHash().hasKey(key, hashKey);
    }

    /**
     * 获取指定 key 和 hashKey 的值
     *
     * @param key  键
     * @param key2 hashKey
     * @return 值的字符串表示；如果不存在返回 null
     */
    public String getMapString(String key, String key2) {
        Object value = redisTemplate.opsForHash().get(key, key2);
        return value != null ? value.toString() : null;
    }

    /**
     * 获取指定 key 和 hashKey 的值
     *
     * @param key  键
     * @param key2 hashKey
     * @return 值的整数表示；如果不存在或不是整数返回 null
     */
    public Integer getMapInt(String key, String key2) {
        Object value = redisTemplate.opsForHash().get(key, key2);
        return value instanceof Integer ? (Integer) value : null;
    }

    /**
     * 弹出元素并删除
     *
     * @param key 键
     * @return 弹出的元素的字符串表示；如果集合为空返回 null
     */
    public String popValue(String key) {
        Object value = redisTemplate.opsForSet().pop(key);
        return value != null ? value.toString() : null;
    }

    /**
     * 删除指定 hash 的 HashKey
     *
     * @param key      键
     * @param hashKeys 要删除的 hashKey
     * @return 删除成功的数量
     */
    public Long delete(String key, String... hashKeys) {
        return redisTemplate.opsForHash().delete(key, hashKeys);
    }

    /**
     * 给指定 hash 的 hashkey 做增减操作
     *
     * @param key     键
     * @param hashKey hashKey
     * @param number  要增加或减少的值
     * @return 操作后的新值
     */
    public Long increment(String key, String hashKey, long number) {
        return redisTemplate.opsForHash().increment(key, hashKey, number);
    }

    /**
     * 给指定 hash 的 hashkey 做增减操作
     *
     * @param key     键
     * @param hashKey hashKey
     * @param number  要增加或减少的值
     * @return 操作后的新值
     */
    public Double increment(String key, String hashKey, Double number) {
        return redisTemplate.opsForHash().increment(key, hashKey, number);
    }

    /**
     * 获取 key 下的所有 hashkey 字段
     *
     * @param key 键
     * @return 包含所有 hashkey 字段的集合
     */
    public Set<Object> hashKeys(String key) {
        return redisTemplate.opsForHash().keys(key);
    }

    /**
     * 获取指定 hash 下面的键值对数量
     *
     * @param key 键
     * @return 键值对的数量
     */
    public Long hashSize(String key) {
        return redisTemplate.opsForHash().size(key);
    }

    //- - - - - - - - - - - - - - - - - - - - -  list类型 - - - - - - - - - - - - - - - - - - - -

    /**
     * 在变量左边添加元素值
     *
     * @param key   键
     * @param value 要添加的元素值
     */
    public void leftPush(String key, Object value) {
        redisTemplate.opsForList().leftPush(key, value);
    }

    /**
     * 获取集合指定位置的值
     *
     * @param key   键
     * @param index 索引位置
     * @return 指定位置的值；如果索引超出范围返回 null
     */
    public Object index(String key, long index) {
        return redisTemplate.opsForList().index(key, index);
    }

    /**
     * 获取指定区间的值
     *
     * @param key   键
     * @param start 起始索引
     * @param end   结束索引
     * @return 指定区间的值组成的列表
     */
    public List<Object> range(String key, long start, long end) {
        return redisTemplate.opsForList().range(key, start, end);
    }

    /**
     * 把最后一个参数值放到指定集合的第一个出现中间参数的前面，如果中间参数值存在的话
     *
     * @param key   键
     * @param pivot 中间参数值
     * @param value 要添加的元素值
     */
    public void leftPush(String key, String pivot, String value) {
        redisTemplate.opsForList().leftPush(key, pivot, value);
    }

    /**
     * 向左边批量添加参数元素
     *
     * @param key    键
     * @param values 要添加的元素值数组
     */
    public void leftPushAll(String key, String... values) {
        redisTemplate.opsForList().leftPushAll(key, values);
    }

    /**
     * 向集合最右边添加元素
     *
     * @param key   键
     * @param value 要添加的元素值
     */
    public void rightPush(String key, String value) {
        redisTemplate.opsForList().rightPush(key, value);
    }

    /**
     * 向左边批量添加参数元素
     *
     * @param key    键
     * @param values 要添加的元素值数组
     */
    public void rightPushAll(String key, String... values) {
        redisTemplate.opsForList().rightPushAll(key, values);
    }

    /**
     * 向已存在的集合中添加元素
     *
     * @param key   键
     * @param value 要添加的元素值
     */
    public void rightPushIfPresent(String key, Object value) {
        redisTemplate.opsForList().rightPushIfPresent(key, value);
    }

    /**
     * 获取集合的长度
     *
     * @param key 键
     * @return 集合的长度
     */
    public long listLength(String key) {
        return redisTemplate.opsForList().size(key);
    }

    /**
     * 移除集合中的左边第一个元素
     *
     * @param key 键
     * @return 移除的元素；如果集合为空返回 null
     */
    public Object leftPop(String key) {
        return redisTemplate.opsForList().leftPop(key);
    }

    /**
     * 移除集合中左边的元素在等待的时间里，如果超过等待的时间仍没有元素则退出
     *
     * @param key     键
     * @param timeout 等待时间
     * @param unit    时间单位
     * @return 移除的元素；如果超时仍没有元素返回 null
     */
    public Object leftPop(String key, long timeout, TimeUnit unit) {
        return redisTemplate.opsForList().leftPop(key, timeout, unit);
    }

    /**
     * 移除集合中右边的元素
     *
     * @param key 键
     * @return 移除的元素；如果集合为空返回 null
     */
    public Object rightPop(String key) {
        return redisTemplate.opsForList().rightPop(key);
    }

    /**
     * 移除集合中右边的元素在等待的时间里，如果超过等待的时间仍没有元素则退出
     *
     * @param key     键
     * @param timeout 等待时间
     * @param unit    时间单位
     * @return 移除的元素；如果超时仍没有元素返回 null
     */
    public Object rightPop(String key, long timeout, TimeUnit unit) {
        return redisTemplate.opsForList().rightPop(key, timeout, unit);
    }
}